home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / cpptask1.zip / TASK.CPP < prev    next >
C/C++ Source or Header  |  1991-02-07  |  4KB  |  181 lines

  1. /**********************************************************************
  2.  *  
  3.  *  NAME:           task.cpp
  4.  *  
  5.  *  DESCRIPTION:    modified version of Bruce Eckel's C++ task manager
  6.  *                  from Computer Language Feb. 1991
  7.  *  
  8.  *  M O D I F I C A T I O N   H I S T O R Y
  9.  *
  10.  *  when        who                 what
  11.  *  -------------------------------------------------------------------
  12.  *  02/04/91    J. Alan Eldridge    created
  13.  *  
  14.  *  02/05/91    JAE                 modified so it would run: made each
  15.  *                                  task have its own stack to eliminate
  16.  *                                  the stack copying (which is not only
  17.  *                                  ugly and limitng, but dangerous as well)
  18.  *  
  19.  *                                  added semaphores for task waiting
  20.  *  
  21.  *********************************************************************/
  22.  
  23. #include    "aedef.h"
  24.  
  25. #include    "task.h"
  26.  
  27. void
  28. tskFatal(char *fmt, ...)
  29. {
  30.     va_list ap;
  31.     
  32.     fprintf(stderr, "TASKER FATAL ERROR: ");
  33.     va_start(ap, fmt);
  34.     vfprintf(stderr, fmt, ap);
  35.     va_end(ap);
  36.     fprintf(stderr, "\n");
  37.     
  38.     exit(EXIT_FAILURE);
  39. }
  40.  
  41. void
  42. TskList::append(TskObj *pObj)
  43. {
  44.     if (!cObj++)
  45.         pHead = pTail = pObj;
  46.     else {
  47.         pTail->linkTo(pObj);
  48.         pTail = pObj;
  49.     }
  50. }
  51.  
  52. void
  53. Task::init()
  54. {
  55.     static Task *saveThis;  //  must be static ...
  56.  
  57.     saveThis = this;    //  ... need to do this 'cause we're changing stacks
  58.                         //  and "this" is an invisible arg on the stack
  59.     stack = (uchar far *) new uchar [ stkLen ]; //  allocate new stack
  60.     
  61.     //  off to Mars ...
  62.     _SP = FP_OFF(stack) + stkLen;
  63.     _SS = FP_SEG(stack);
  64.     
  65.     //  call using saved value ...
  66.     saveThis->tskMain(); //  ... and never come back
  67.  
  68.     //  if we get here, something's _really_ wrong ...
  69.     tskFatal("returned from tskMain() in task %s\n", name());
  70. }
  71.  
  72. void
  73. Task::suspend()
  74. {
  75.     if (!setjmp(tskEnv))
  76.         owner.giveUpTask();
  77. }
  78.  
  79. void
  80. Task::resume()
  81. {
  82.     longjmp(tskEnv, 1);
  83. }
  84.  
  85. void
  86. Scheduler::runATask()
  87. {
  88.     int cTask = tasks.count();
  89.     
  90.     for (int n = 0; n < cTask; n++) {
  91.         if (pTask)
  92.             pTask = (Task *)(pTask->next());
  93.         if (!pTask)
  94.             pTask = (Task *)(tasks.first());
  95.         
  96.         if (!pTask->isReady())
  97.             continue;
  98.         if (!pTask->isInited())
  99.             pTask->init();    //  never return except by longjmp()
  100.                                      //  to setjmp() at beginning of function
  101.         else
  102.             pTask->resume();  //  just go back after last suspend()
  103.     }
  104. }
  105.  
  106. void
  107. Scheduler::run()
  108. {
  109.     if (setjmp(schEnv) == -1)   //  look for endProcess() call
  110.         return;
  111.  
  112.     runATask(); //  try to run next available task
  113.     
  114.     tskFatal("deadlock!! all tasks are blocked");
  115. }
  116.  
  117. Task::Task(uchar *name, Scheduler &s, int len): 
  118.     tName(name), owner(s), stkLen(len), stack(0), ready(1)
  119. {
  120.     owner.addTask(this);
  121. }
  122.  
  123. Task::~Task()   //  note this is a virtual function
  124. {
  125.     delete stack;
  126. }
  127.  
  128. Sema *
  129. Scheduler::findSema(uchar *semaName)
  130. {
  131.     for (Sema *pSema = (Sema *)(semas.first()); pSema; 
  132.             pSema = (Sema *)(pSema->next()))
  133.         if (!strcmp(semaName, pSema->name()))
  134.             break;
  135.  
  136.     if (!pSema)
  137.         tskFatal("semaphore %s not found", semaName);
  138.  
  139.     return pSema;
  140. }    
  141.  
  142. void
  143. Scheduler::signalSema(uchar *semaName, Task *t, int units)
  144. {
  145.     findSema(semaName)->signal(t, units);
  146. }
  147.  
  148. void
  149. Scheduler::waitSema(uchar *semaName, Task *t)
  150. {
  151.     findSema(semaName)->wait(t);
  152. }
  153.  
  154. void
  155. Sema::signal(Task *t, int units)
  156. {
  157.     value += units;
  158.     if (value > 0 && tskWaiting) {
  159.         tskWaiting->makeReady();
  160.         tskWaiting = 0;
  161.     }
  162.     t->suspend();
  163. }
  164.  
  165. void
  166. Sema::wait(Task *t)
  167. {
  168.     if (tskWaiting)
  169.         tskFatal("task %s tried to wait on semaphore %s, "  //  no comma!
  170.             "already used by task %s",
  171.             t->name(), name(), tskWaiting->name());
  172.  
  173.     tskWaiting = t;
  174.     if (value > 0)  //  handle initial case where sema is disabled
  175.         value--;    //  but nobody's waiting on it yet
  176.     if (value < 1) {
  177.         t->makeWait();
  178.         t->suspend();
  179.     }
  180. }
  181.